using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WinFileHistory
{
    public static class ClsExts
    {
        private static System.Text.RegularExpressions.Regex rxOrgName = new System.Text.RegularExpressions.Regex(@"(.*)(\s+\(\d{4}_\d{2}_\d{2}\s+\d{2}_\d{2}_\d{2}\s+UTC\))(\.?[^$]*)"); //| "test (2019_10_10 08_28_02 UTC).html" => "test.html"

        /// <summary>
        /// IMK: 转换文件路径名，去除时间信息
        /// </summary>
        /// <param name="file_path">D:/www/A (2023-01-01 12:00:00 UTC).txt</param>
        /// <param name="old_file_path">D:/www/A.txt</param>
        /// <returns></returns>
        public static bool TryToFilePath(this string file_path, out string old_file_path)
        {
            System.Text.RegularExpressions.Match mt = rxOrgName.Match(file_path);
            if (mt.Success && mt.Groups.Count == 4)
            {
                old_file_path = mt.Groups[1].Value + mt.Groups[3].Value;
                return true;
            }
            else
            {
                old_file_path = file_path;
                return false;
            }
        }

        public static string ToGB(this long length, int digits = 0)
        {
            return (length / 1024 / 1024 / 1024F).ToString("F"+digits) + " GB";
        }

        public static string ToXB(this long length, int digits = 0)
        {
            if (length > 0x40000000) //|G
            {
                return (length / 1024 / 1024 / 1024F).ToString("F" + digits) + " GB";
            }
            else if (length > 0x100000) //|M
            {
                return (length / 1024 / 1024F).ToString("F" + digits) + " MB";
            }
            else if (length > 0x400) //|K
            {
                return (length / 1024F).ToString("F" + digits) + " KB";
            }
            else { return length + "B"; }
        }

        public static bool IsExclude(this List<string> excludes, string path)
        {
            foreach (string exc in excludes)
            {
                if ((exc.StartsWith("//") || exc.IndexOf(":") >= 0) && path.StartsWith(exc, StringComparison.CurrentCultureIgnoreCase))
                {
                    return true;
                }
                else if (path.IndexOf(exc, StringComparison.CurrentCultureIgnoreCase) >= 0)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// IMK: 计算相对路径
        /// </summary>
        /// <param name="path1"></param>
        /// <param name="path2"></param>
        /// <returns></returns>
        /// <example>GetRelativePath("c:/www/book1/index.html","c:/www/");</example>
        public static string GetRelativePath(string path1, string path2, bool ignoreCase = false)
        {
            string[] path1Array = path1.Replace("\\", "/").Split('/');
            string[] path2Array = path2.Replace("\\", "/").Split('/');

            int s = path1Array.Length >= path2Array.Length ? path2Array.Length : path1Array.Length;
            //两个目录最底层的共用目录索引
            int closestRootIndex = -1;
            for (int i = 0; i < s; i++)
            {
                //if (path1Array[i] == path2Array[i])
                if (string.Equals(path1Array[i], path2Array[i], ignoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture))
                {
                    closestRootIndex = i;
                }
                else
                {
                    break;
                }
            }
            //由path1计算 ‘../’部分
            string path1Depth = "";
            if (closestRootIndex >= 0) //IMK: have same part
            {
                for (int i = 0; i < path1Array.Length; i++)
                {
                    if (i > closestRootIndex + 1)
                    {
                        path1Depth += "../";
                    }
                }
            }
            //由path2计算 ‘../’后面的目录
            string path2Depth = "";
            for (int i = closestRootIndex + 1; i < path2Array.Length; i++)
            {
                path2Depth += "/" + path2Array[i];
            }
            path2Depth = path2Depth.Substring(1);

            return path1Depth + path2Depth;
        }

        public static char GetNextLogicalDisk()
        {
            var arr = Environment.GetLogicalDrives();
            for (char i='Z'; i>='A'; i--)
            {
                if (!arr.Contains(i + @":\")) { return i; }
            }
            return 'Z';
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string ResolveToUNC(string path)
        {
            if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException("The path argument was null or whitespace."); }

            if (!System.IO.Path.IsPathRooted(path)) { throw new ArgumentException(string.Format("The path '{0}' was not a rooted path and ResolveToUNC does not support relative paths.", path));}

            // Is the path already in the UNC format?
            if (path.StartsWith(@"\"))
            {
                return path;
            }

            string rootPath = ResolveToRootUNC(path);

            if (path.StartsWith(rootPath))
            {
                return path; // Local drive, no resolving occurred
            }
            else
            {
                return path.Replace(GetDriveLetter(path), rootPath);
            }
        }

        public static string ResolveToRootUNC(string path)
        {
            if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException("The path argument was null or whitespace."); }

            if (!System.IO.Path.IsPathRooted(path)) { throw new ArgumentException(string.Format("The path '{0}' was not a rooted path and ResolveToRootUNC does not support relative paths.", path)); }

            if (path.StartsWith(@"\")) { return System.IO.Directory.GetDirectoryRoot(path); }

            // Get just the drive letter for WMI call
            string driveletter = GetDriveLetter(path);

            // Query WMI if the drive letter is a network drive, and if so the UNC path for it
            using (System.Management.ManagementObject mo = new System.Management.ManagementObject())
            {
                mo.Path = new System.Management.ManagementPath(string.Format("Win32_LogicalDisk='{0}'", driveletter));

                System.IO.DriveType driveType = (System.IO.DriveType)((uint)mo["DriveType"]);
                string networkRoot = Convert.ToString(mo["ProviderName"]);

                if (driveType == System.IO.DriveType.Network)
                {
                    return networkRoot;
                }
                else
                {
                    return driveletter + System.IO.Path.DirectorySeparatorChar;
                }
            }
        }
        public static string GetDriveLetter(string path)
        {
            if (String.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException("The path argument was null or whitespace."); }

            if (!System.IO.Path.IsPathRooted(path)) { throw new ArgumentException(string.Format("The path '{0}' was not a rooted path and GetDriveLetter does not support relative paths.",path)); }

            if (path.StartsWith(@"\")) { throw new ArgumentException("A UNC path was passed to GetDriveLetter"); }

            return System.IO.Directory.GetDirectoryRoot(path).Replace(@"\", "").Replace("/", "");
        }
    }
}
